package sms

import (
	"fmt"
	"gitee.com/mootok/mootok/src/constant/config"
	"gitee.com/mootok/mootok/src/constant/strings"
	redis2 "gitee.com/mootok/mootok/src/constant/strings/redis"
	"gitee.com/mootok/mootok/src/external_service/sms"
	"gitee.com/mootok/mootok/src/storage/redis"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis_rate/v10"
)

type Service struct {
}

var userRegisterAndLoginCacheCodePrefix = config.EnvConfig.RedisPrefix + "user_register_and_login_cache_code:"

func genAuthCodeKey(phone string) string {
	return fmt.Sprintf("%s%s", userRegisterAndLoginCacheCodePrefix, phone)
}

var userRegisterAndLoginCacheCodeLimitKeyPrefix = config.EnvConfig.RedisPrefix + "user_register_and_login_code_freq_limit"

func genUserRegisterAndLoginCacheCodeLimitKey(key string) string {
	return fmt.Sprintf("%s%s", userRegisterAndLoginCacheCodePrefix, key)
}

var registerAndLoginSmsMaxQPS = 1

func (*Service) RegisterAndLoginSmsLimit(c *gin.Context, phone string) (bool, error) {
	//ip地址限流
	ip := c.ClientIP()
	limiterKey := genUserRegisterAndLoginCacheCodeLimitKey(ip)
	limiter := redis_rate.NewLimiter(redis.Client)
	limiterRes, err := limiter.Allow(c, limiterKey, redis_rate.PerMinute(registerAndLoginSmsMaxQPS))
	if err != nil {
		return false, err
	}
	//次数上限
	if limiterRes.Allowed == 0 {
		return false, nil
	}
	//手机号限流
	limiterKey = genUserRegisterAndLoginCacheCodeLimitKey(phone)
	limiterRes, err = limiter.Allow(c, limiterKey, redis_rate.PerMinute(registerAndLoginSmsMaxQPS))
	if err != nil {
		return false, err
	}
	//次数上限
	if limiterRes.Allowed == 0 {
		return false, nil
	}
	return true, nil
}

func (*Service) GetAuthCode(c *gin.Context, phone string) (string, error) {
	redisKey := genAuthCodeKey(phone)
	codeCache, err := redis.Client.Get(c, redisKey).Result()
	return codeCache, err
}

func (*Service) SendAuthCode(c *gin.Context, phone string, code string) error {
	redisKey := genAuthCodeKey(phone)

	if err := redis.Client.Set(c, redisKey, code, redis2.UserRegisterAndLoginCacheCodeExpireTime).Err(); err != nil {
		return err
	}

	if err := sms.Instance.Send(phone, fmt.Sprintf(strings.SmsAuthCodeTemplate, code)); err != nil {
		return err
	}
	return nil
}
